package mmi.file;

import java.awt.Color;
import java.awt.Font;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import mmi.gui.shape.FreeLine;
import mmi.gui.shape.Shape;
import mmi.gui.shape.TextObject;
import mmi.gui.shape.Shape.Shapes;
import mmi.utils.Action;
import mmi.utils.Action.Actions;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * ReadFile contains some functions to read from (XML) files.
 * @see WriteFile
 * 
 * @author louis
 *
 */
public class ReadFile {

	private Document dom;

	private Vector<Action> actionList = new Vector<Action>();

	/**
	 * Default constructor
	 * @param file the file that contains the XML representation of actions
	 */
	public ReadFile(File file)
	{
		parseXmlFile(file.getAbsolutePath());
		parseDocument();
	}

	/**
	 * 
	 * @param actionElement
	 * @return
	 */
	private Action getAction(Element actionElement)
	{

		Shape shape = getShape(actionElement, "Shape");
		Timestamp timestamp = getTimestampValue(actionElement,"Timestamp");

		Actions action = Action.getAction(actionElement.getAttribute("type"));

		Vector<Shape> shapeList = new Vector<Shape>();

		// get a nodelist of <employee> elements
		NodeList nl = actionElement.getElementsByTagName("Shape");
		if (nl != null && nl.getLength() > 0) {


			for (int i = 0; i < nl.getLength(); i++) {

				Element el = (Element) nl.item(i);
				shapeList.add(getShape(el));
			}
		}

		Shape s = shapeList.firstElement();
		if(s != null && s.getShape().equals(Shape.Shapes.FreeLine))
		{
			FreeLine fl = (FreeLine) s;

			for(int i=1; i < shapeList.size(); i++)
			{
				fl.addPoint(new Point2D.Double(shapeList.get(i).getStart().getX(), shapeList.get(i).getStart().getY()));
			}
		}

		// add it to list
		actionList.add(new Action(action, s, timestamp));

		//		return null;
		return new Action(action, shape, timestamp);
	}

	/**
	 * @return the actionList
	 */
	public Vector<Action> getActionList() {
		return actionList;
	}

	/**
	 * 
	 * @param actionElement
	 * @return
	 */
	private Shape getShape(Element actionElement) {

		//for each <employee> element get text or int values of
		//name ,id, age and name
		//		Shape shape = getShape(actionElement, "Shape");
		//		Timestamp timestamp = getTimestampValue(actionElement,"Timestamp");

		//		Point2D start = new Point2D.Double(getDoubleValue(actionElement, "xstart"), getDoubleValue(actionElement, "ystart"));
		//		Point2D end = new Point2D.Double(getDoubleValue(actionElement, "xend"), getDoubleValue(actionElement, "yend"));

		//		Shape shape = Shape.createShape(Shape.getShape(actionElement.getAttribute("shapetype")), start, end);

		//		return shape;
		return null;
	}

	/**
	 * 
	 * @param ele
	 * @param tagName
	 * @return
	 */
	private Shape getShape(Element ele, String tagName)
	{
		Shape shape = null;

		NodeList nl = ele.getElementsByTagName(tagName);
		if (nl != null && nl.getLength() > 0) {
			Element el = (Element) nl.item(0);

			NamedNodeMap nnm = el.getAttributes();

			Point2D start = null;
			if(nnm.getNamedItem("xstart") != null && nnm.getNamedItem("ystart") != null)
			{
				start = new Point2D.Double(Double.parseDouble(nnm.getNamedItem("xstart").getNodeValue()), Double.parseDouble(nnm.getNamedItem("ystart").getNodeValue()));
			}

			Point2D middle = null;
			if(nnm.getNamedItem("xmiddle") != null && nnm.getNamedItem("ymiddle") != null)
			{
				middle = new Point2D.Double(Double.parseDouble(nnm.getNamedItem("xmiddle").getNodeValue()), Double.parseDouble(nnm.getNamedItem("ymiddle").getNodeValue()));
			}

			Point2D end = null;
			if(nnm.getNamedItem("xend") != null && nnm.getNamedItem("yend") != null)
			{
				end = new Point2D.Double(Double.parseDouble(nnm.getNamedItem("xend").getNodeValue()), Double.parseDouble(nnm.getNamedItem("yend").getNodeValue()));
			}






			Shape.Shapes shapeType = Shape.getShape(el.getFirstChild().getNodeValue());

			if(shapeType != null) {
				if(shapeType.equals(Shape.Shapes.Text))
				{
					Font font = Font.decode(nnm.getNamedItem("font").getNodeValue());
					Color colour = Color.decode(nnm.getNamedItem("colour").getNodeValue());
					String text = nnm.getNamedItem("text").getNodeValue();
					shape = new TextObject(/*id,*/ start, text, font, colour);

				} else
				{

					Color lineColour = Color.decode(nnm.getNamedItem("linecolour").getNodeValue());
					int lineWidth = Integer.parseInt(nnm.getNamedItem("lineWidth").getNodeValue());
					if(shapeType.equals(Shape.Shapes.FreeLine))
					{
						shape = Shape.createShape(Shapes.FreeLine, start, end, lineColour, lineColour, lineWidth);
						shape = new FreeLine(/*id,*/ start, end, lineColour, lineWidth);
					} else
					{
						Color fillColour = Color.decode(nnm.getNamedItem("fillcolour").getNodeValue());
						shape = Shape.createShape(shapeType, start, end, lineColour, fillColour, lineWidth);
					}
				}
			}

			if(middle != null) {
				shape.setMiddle(middle);
			}
		}

		return shape;
	}

	/**
	 * Takes a xml element and the tag name. It looks for the tag, and it takes the corresponding
	 * text.
	 * 
	 * @param ele
	 * @param tagName
	 * @return
	 */
	private String getTextValue(Element ele, String tagName)
	{
		String textVal = null;
		NodeList nl = ele.getElementsByTagName(tagName);
		if (nl != null && nl.getLength() > 0)
		{
			Element el = (Element) nl.item(0);
			textVal = el.getFirstChild().getNodeValue();
		}

		return textVal;
	}

	/**
	 * Takes a xml element and the tag name. It looks for the tag, and it takes the corresponding
	 * text if it's a timestamp.
	 * @param ele
	 * @param tagName
	 * @return
	 */
	private Timestamp getTimestampValue(Element ele, String tagName)
	{
		Timestamp ts = null;
		NodeList nl = ele.getElementsByTagName(tagName);
		if (nl != null && nl.getLength() > 0)
		{
			Element el = (Element) nl.item(0);
			ts = Timestamp.valueOf(el.getFirstChild().getNodeValue());
		}

		return ts;
	}

	/**
	 * Parses the document
	 */
	private void parseDocument() {
		// get the root elememt
		Element docEle = dom.getDocumentElement();

		NodeList nl = docEle.getElementsByTagName("Action");
		if (nl != null && nl.getLength() > 0)
		{
			for (int i = 0; i < nl.getLength(); i++)
			{
				Element el = (Element) nl.item(i);

				getAction(el);

				//				// add it to list
				//				actionList.add(a);
			}
		}
	}
	/**
	 * Parses the XML file
	 * @param fileName the file name of the file that contains the XML representation of actions
	 */
	private void parseXmlFile(String fileName)
	{
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

		try
		{
			DocumentBuilder db = dbf.newDocumentBuilder();

			// parse using builder to get DOM representation of the XML file
			dom = db.parse(fileName);
		} catch (ParserConfigurationException pce)
		{
			pce.printStackTrace();
		} catch (SAXException se)
		{
			se.printStackTrace();
		} catch (IOException ioe)
		{
			ioe.printStackTrace();
		}
	}

}
